package com.studerb.tasks.headers;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.commons.net.io.DotTerminatedMessageReader;
import org.apache.commons.net.nntp.NNTP;
import org.apache.commons.net.nntp.NNTPCommand;
import org.apache.commons.net.nntp.NNTPReply;
import org.springframework.beans.factory.annotation.Autowired;

import com.studerb.model.Post;
import com.studerb.service.interfaces.IDecodingService;
import com.studerb.service.interfaces.IHeaderService;
import com.studerb.tasks.AbstractTask;
import com.studerb.util.Constants;

public class BodyCommandTask extends AbstractTask<Void, Void> {
	@Autowired private IDecodingService decodingService;
	@Autowired private IHeaderService headerService;
	private Post post;
	private int linesRead = 0;

	private void checkProgress() {
		// server inserts extra blank lines that are not included in header
		// provided 'lineCount'
		// int tempLineCount = linesRead > post.getLineCount() ?
		// post.getLineCount() : linesRead;
		// logger.debug(String.format("Setting progress: %d / %d / %d",
		// this.linesRead, 0, this.header.getLineCount() +
		// 1));
		// setProgress(tempLineCount, 0, post.getLineCount() + 1);
		setProgress(RandomUtils.nextInt(100));
	}

	private void doGroupCommand() throws IOException {
		setProgress(5);
		setMessage("Sending Group Command");
		if (post.getNewsGroup() == null) {
			throw new IllegalStateException("Must set newsgroup before executing");
		}
		groupCommandReply = nntpConnection.groupCommand(post.getNewsGroup().getGroupName());
		logger.debug("Group command reply: " + nntpConnection.getReplyString());
	}

	@Override protected Void doInBackground() throws Exception {
		String currentLine;
		setTitle("Downloading body: " + post.getArticleNumber());
		BufferedReader bufferedReader = null;
		ByteArrayOutputStream output = null;
		try {

			doGroupCommand();
			setMessage("Sending BODY Command");
			int reply = nntpConnection.sendCommand(NNTPCommand.BODY, post.getArticleNumber().toString());
			if (reply != NNTPReply.ARTICLE_RETRIEVED_BODY_FOLLOWS) {
				throw new IOException("Bad reply to BODY command: " + nntpConnection.getReplyString());
			}
			bufferedReader = new BufferedReader(new DotTerminatedMessageReader(nntpConnection.getReader()));
			output = new ByteArrayOutputStream();
			// get rid of first blank line;

			byte[] newLineBytes = new byte[] { '\r', '\n' };
			/*
			 * if(currentLine.length() != 0){ throw new RuntimeException("Body
			 * command's first line should be empty - instead got: " +
			 * currentLine); }
			 */
			setMessage("Downloading BODY" + post.getArticleNumber());
			while (!isCancelled()) {
				currentLine = bufferedReader.readLine();
				if (currentLine == null) {
					break;
				} else {
					linesRead++;
					output.write(currentLine.getBytes(NNTP.DEFAULT_ENCODING));
					output.write(newLineBytes);
					checkProgress();
				}
			}

			headerService.setArticleDownloaded(post);
			File outputFile = File.createTempFile(String.valueOf(post.getArticleNumber()) + "_body", Constants.DECODED_FILE_SUFFIX);
			FileUtils.writeByteArrayToFile(outputFile, output.toByteArray());
			logger.info("wrote encoded BODY bytes to: " + outputFile.getAbsolutePath());
			// File decodedFile = decodingService.decodeArticle(header,
			// output.toByteArray());
			// logger.debug(String.format(
			// "decoded filename %s \nFrom Fileheader (subject): %s",
			// decodedFile.getAbsolutePath(), header.getSubject()));
			return null;
		} finally {
			IOUtils.closeQuietly(output);
			IOUtils.closeQuietly(bufferedReader);
		}
	}

	public Post getPost() {
		return post;
	}

	@Override public void init() {
		title = "Downloading Body";
		determinable = true;
		connectionNeeded = true;
	}

	public void setPost(Post post) {
		this.post = post;
	}
}
